package com.jandar.parser.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.jandar.Resources;
import com.jandar.parser.BaseParser;
import com.jandar.parser.exception.ParserException;
import com.jandar.table.config.Column;
import com.jandar.table.config.ColumnTypeInfo;
import com.jandar.table.config.IdGeneratorInfo;
import com.jandar.table.config.Table;
import com.jandar.util.DBUtils;
import com.jandar.util.DateUtils;
import com.jandar.util.ExceptionUtils;
import com.jandar.util.SQLUtils;

/**
 * TXT解析器。
 * 
 * @author pqj
 * @version 2009-6-10
 */
public class TXTParser extends BaseParser {

	/** 分隔符匹配模式 */
	private static final String SEPARATOR_REGEX = "[" + Resources.getInstance().getTxtSeparator()
			+ "\r\n]";

	/** 文本文件分隔符匹配模式 */
	private Pattern txtPattern = Pattern.compile(SEPARATOR_REGEX);

	/**
	 * 插入或者更新操作。 以最大限度处理文件中的记录，有出错的记录，写入日志。 统计插入条数、更新条数、失败条数。
	 * 
	 * @param conn 数据库连接
	 * @param file 指定文件
	 * @throws Exception 异常
	 */
	public void insertOrUpdate(Connection conn, File file) throws Exception {
		super.insertOrUpdate(conn, file);

		String dataTitleLine = "";
		String tableName = super.getTableName(file);
		Table table = Resources.getInstance().getTableCfgMap().get(tableName);
		if (table == null) {
			throw new ParserException("找不到表：<" + tableName + ">的配置信息！");
		}

		BufferedReader reader = null;
		ResultSet result = null;
		Statement statement = conn.createStatement();
		String failureFileName = Resources.getInstance().getErrfolder().getAbsolutePath() + "\\"
				+ getFailureRecordFileName(tableName, new Date());

		Column[] columns = table.getAllColumn();
		IdGeneratorInfo generatorInfo = SQLUtils.getIdGenerator(table.getId());
		int idSize = table.getIdCount();
		reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
		// 返回录入字段第一列所对应的数据库字段下标
		int columnIndex = getColumnFirstIndex(generatorInfo, idSize);
		try {
			String line = null;
			int option = 0;
			StringBuilder lineBuf = new StringBuilder();
			int quotesCount = 0;

			// 数据文件第一行是否含有标题
			boolean dataTitle = Resources.getInstance().isDataTitle();
			if (dataTitle) {
				dataTitleLine = reader.readLine() + NEWLINE;
			}

			while ((line = reader.readLine()) != null) {
				// 强制中断标志
				if (cancelled) {
					throw new ParserException("文本解析异常中断！");
				}
				
				line = line + NEWLINE;
				lineBuf.append(line);
				quotesCount += getQuotesCount(line);
				if (quotesCount > 0 && (quotesCount % 2) != 0) {
					continue;
				}

				String[] values = null;
				try {
					values = getValues(lineBuf.toString(), columns, columnIndex);
					if (values == null) {
						throw new ParserException("导入文件格式错误！");
					}
					// 查看数据库是否有数据
					String selectSQL = SQLUtils.createSelectCountSQL(tableName, values);
					logger.debug("查询记录是否存在SQL： " + selectSQL);
					result = statement.executeQuery(selectSQL);

					String operateSQL = null;
					// 数据库已经存在该记录
					if (result.next() && result.getInt(1) > 0) {
						operateSQL = SQLUtils.createUpdateSQL(tableName, values);
						option = UPDATE_OPTION;
						// 数据库没有存在该记录
					} else {
						operateSQL = SQLUtils.createInsertSQL(tableName, values);
						option = INSERT_OPTION;
					}

					logger.debug("操作记录SQL： " + operateSQL);
					statement.executeUpdate(operateSQL);
					if (INSERT_OPTION == option) {
						++insertCount;
					} else {
						++updateCount;
					}
				} catch (Exception e) {
					ExceptionUtils.error(e);
					++failureCount;
					// 写入日志文件
					writeFailureRecord(failureFileName, lineBuf.toString());

				} finally {
					try {
						DBUtils.closeResultSet(result);
					} catch (SQLException e) {
						ExceptionUtils.error(e);
					}
				}

				lineBuf.delete(0, lineBuf.length());
				quotesCount = 0;
			}

			// 导入文件格式错误——引号只出现了半个
			if (lineBuf.length() > 0) {
				// 写入日志文件
				writeFailureRecord(failureFileName, lineBuf.toString());
			}
		} finally {
			if (reader != null) {
				reader.close();
			}

			try {
				DBUtils.closeStatement(statement);
			} catch (SQLException e) {
				ExceptionUtils.error(e);
			}
		}
	}

	/**
	 * 取得一行文本所包含的字段值。
	 * 
	 * @param text 一行文本
	 * @param column 数据库全字段
	 * @param columnIndex 返回录入字段第一列所对应的数据库字段下标
	 * @return 字段值
	 */
	private String[] getValues(String text, Column[] column, int columnIndex) throws Exception {

		String line = text.replaceAll(NEWLINE, "") + "\r";
		String[] values = new String[column.length];
		Matcher matcher = txtPattern.matcher(line);
		int start = 0;
		int index = 0;

		while (matcher.find()) {
			int end = matcher.end() - 1;
			String value = line.substring(start, end);
			int quotesCount = getQuotesCount(value);

			// 有一个引号
			if (quotesCount == 1) {

				int quotesIndex = line.indexOf("\"", end + 1);
				value = (value + line.substring(end, quotesIndex)).replace("\"", "");
				// 移动匹配器的匹配位置
				while (matcher.find()) {
					if (matcher.end() > quotesIndex) {
						end = matcher.end() - 1;
						break;
					}
				}

				// 有两个引号
			} else if (quotesCount == 2) {

				value = value.replace("\"", "");

				// 格式错误或者数据库里面的值存在特殊字符——引号
			} else if (quotesCount > 2) {
				return null;
			}

			if ("".equals(value)) {
				value = null;
			} else {
				ColumnTypeInfo columnType = column[columnIndex].getType();
				if (ColumnTypeInfo.DATE == columnType) {
					String format = column[columnIndex].getFormat();
					if (format == null || "".equals(format)) {
						format = SQLUtils.DEFAULT_DATE_PATTERN;
					}
					value = DateUtils.format(format, SQLUtils.DEFAULT_DATE_PATTERN, value);
				} else if (ColumnTypeInfo.DATETIME == columnType) {
					String format = column[columnIndex].getFormat();
					if (format == null || "".equals(format)) {
						format = SQLUtils.DEFAULT_DATETIME_PATTERN;
					}
					value = DateUtils.format(format, SQLUtils.DEFAULT_DATETIME_PATTERN, value);
				}
			}

			values[index++] = value;
			start = end + 1;
			columnIndex++;
		}
		return values;
	}

	/**
	 * 返回引号个数。
	 * 
	 * @param line 字符串
	 * @return 引号个数
	 */
	private int getQuotesCount(String line) {
		int index = -1;
		int count = 0;
		while ((index = line.indexOf('\"', index + 1)) != -1) {
			++count;
		}
		return count;
	}
}
